package worker

import (
	"context"
	"errors"
	"fmt"
	"time"

	"zhonghui/console/warehouse/cfgx"
	"zhonghui/console/warehouse/dbx"
	"zhonghui/console/warehouse/dbx/cache_main"
	"zhonghui/console/warehouse/logx"
	"zhonghui/console/wxutil"

	jsoniter "github.com/json-iterator/go"

	"github.com/ddliu/go-httpclient"
)

// SuiteAccessTokenWorker 刷新开放平台SuiteAccessToken
type SuiteAccessTokenWorker struct{}

func (w *SuiteAccessTokenWorker) Start() {
	w.do()
	t := time.NewTicker(60 * time.Second)
	for {
		select {
		case <-t.C:
			w.do()
		}
	}
}

func (w *SuiteAccessTokenWorker) do() {
	defer func() {
		if r := recover(); r != nil {
			logx.Zap().Errorw("定时任务异常",
				"err", errors.New(fmt.Sprintf("%s", r)),
			)
		}
	}()

	rc := cache_main.Client()
	lock, ch, err := dbx.GetRedisLockWithRefresh(rc, dbx.RedisPrefix("locker-SuiteAccessTokenWorker"), 5*time.Second, time.Second)
	if err != nil {
		return
	}
	defer func() {
		if ch != nil {
			ch <- 1
		}
		lock.Release(context.Background())
	}()

	logx.Zap().Infow("开始检查suite_access_token,获取锁成功")
	cfg := cfgx.Cfg().GetStringMapString("wx")

	// 获取token的有效时间
	t, err := wxutil.SuiteAccessTokenTtl(cfg["suite_id"])
	if err != nil {
		logx.Zap().Errorw("suite_access_token从缓存获取失败", "err", err)
		return
	}

	// 如果大于10分钟则有效
	if t.Seconds() > 600 {
		logx.Zap().Infow("suite_access_token当前有效期", "ttl", t.Seconds())
		return
	}

	logx.Zap().Infow("suite_access_token未找到开始获取")

	// 检查锁
	if true != dbx.HasRedisLock(lock) {
		logx.Zap().Warnw("请求前没有锁放弃写入")
		return
	}

	// 获取ticket
	tk, err := wxutil.GetSuiteTicket(cfg["suite_id"])
	if err != nil {
		logx.Zap().Errorw("suite ticket从缓存获取失败", "err", err)
		return
	}

	body := struct {
		SuiteId     string `json:"suite_id"`
		SuiteSecret string `json:"suite_secret"`
		SuiteTicket string `json:"suite_ticket"`
	}{
		SuiteId:     cfg["suite_id"],
		SuiteSecret: cfg["secret"],
		SuiteTicket: tk,
	}
	host := cfgx.Cfg().GetString("wx.host")
	res, err := httpclient.PostJson(fmt.Sprintf("%s/cgi-bin/service/get_suite_token", host), body)
	if err != nil {
		logx.Zap().Errorw("获取suite_access_token失败", "err", err)
		return
	}
	ret, err := res.ToString()
	if err != nil {
		logx.Zap().Errorw("获取suite_access_token失败", "err", err)
		return
	}

	// 解析返回数据
	data := struct {
		ErrCode          int64  `json:"errcode"`
		ErrMsg           string `json:"errmsg"`
		SuiteAccessToken string `json:"suite_access_token"`
		ExpiresIn        int64  `json:"expires_in"`
	}{}
	if err := jsoniter.Unmarshal([]byte(ret), &data); err != nil {
		logx.Zap().Errorw("解析suite_access_token失败", "err", err)
		return
	}

	// 业务失败
	if data.ErrCode != 0 {
		logx.Zap().Errorw("获取suite_access_token失败", "err", errors.New(data.ErrMsg))
		return
	}

	// 开始保存
	if err := wxutil.SetSuiteAccessToken(cfg["suite_id"], data.SuiteAccessToken); err != nil {
		logx.Zap().Errorw("写入suite_access_token失败", "err", err)
		return
	}

	logx.Zap().Infow("写入suite_access_token成功")
}
